#include <assert.h>
#include <iostream>

#include "building_type.hpp"
#include "city.hpp"
#include "foreach.hpp"
#include "hex_geometry.hpp"
#include "project.hpp"
#include "terrain.hpp"
#include "terrain_improvement.hpp"
#include "world.hpp"

project::project(city* c) : city_(c), labor_complete_(0), labor_required_(0)
{
}

project::~project()
{
}

int project::labor_complete() const
{
	return labor_complete_;
}

int project::labor_required() const
{
	return labor_required_;
}

void project::apply_labor(int amount)
{
	labor_complete_ += amount;
}

bool project::complete() const
{
	return labor_required_ <= labor_complete_;
}

void project::draw() const
{
	foreach(const hex::location& loc, locs()) {
		draw_loc(loc);
	}
}

void project::set_locs(const std::vector<hex::location>& locs)
{
	locs_ = locs;
}

void project::set_labor_requirement(int amount)
{
	labor_required_ = amount;
}

road_project::road_project(const world& w, city* c, const std::vector<hex::location>& path)
  : project(c)
{
	set_locs(path);

	int labor = 0;
	for(int i = 0; i < locs().size() - 1; ++i) {
		assert(w.map().is_loc_on_map(locs()[i]));
		assert(w.map().is_loc_on_map(locs()[i+1]));
		labor += w.map().get_tile(locs()[i])->terrain()->move_cost();
		labor += w.map().get_tile(locs()[i+1])->terrain()->move_cost();
	}
	set_labor_requirement(labor);
}

void road_project::draw_loc(const hex::location& loc) const
{
	std::vector<hex::location>::const_iterator itor = std::find(locs().begin(), locs().end(), loc);
	if(itor == locs().end()) {
		return;
	}

	glDisable(GL_TEXTURE_2D);
	glLineWidth(8);
	glBegin(GL_LINES);
	glColor4f(0.5, 0.3, 0.3, 0.5);

	const int src_pixel_x = tile_pixel_x(*itor) + HexSize/2;
	const int src_pixel_y = tile_pixel_y(*itor) + HexSize/2;

	if(itor + 1 != locs().end()) {
		const int dst_pixel_x = tile_pixel_x(*(itor + 1)) + HexSize/2;
		const int dst_pixel_y = tile_pixel_y(*(itor + 1)) + HexSize/2;

		glVertex3f(src_pixel_x, src_pixel_y, 0);
		glVertex3f(dst_pixel_x, dst_pixel_y, 0);
	}

	glColor4f(1.0, 1.0, 1.0, 1.0);
	glEnd();
	glEnable(GL_TEXTURE_2D);
	glLineWidth(1);
}

std::string road_project::description() const
{
	return "Road";
}

void road_project::do_apply(world& w)
{
	std::cerr << "applying: " << locs().size() << "\n";
	for(int n = 0; n < locs().size() - 1; ++n) {
		if(locs()[n] == locs()[n+1]) {
			continue;
		}

		const hex::tile_ptr t1 = w.map().get_tile(locs()[n]);
		const hex::tile_ptr t2 = w.map().get_tile(locs()[n+1]);
		assert(t1);
		assert(t2);
		const hex::DIRECTION dir1 = hex::get_adjacent_direction(locs()[n], locs()[n+1]);
		const hex::DIRECTION dir2 = hex::get_adjacent_direction(locs()[n+1], locs()[n]);
		t1->build_road(dir1);
		t2->build_road(dir2);
	}
}

building_project::building_project(city_ptr c, const_building_type_ptr b)
  : project(c.get()), city_(c), building_(b)
{
	set_labor_requirement(building_->cost());
}

std::string building_project::description() const
{
	return "Build " + building_->id();
}

void building_project::do_apply(world& w)
{
	city_->add_building(building_);
}

void building_project::draw_loc(const hex::location& loc) const
{
}

improvement_project::improvement_project(city_ptr c, hex::tile_ptr t)
  : project(c.get()), city_(c), tile_(t)
{
	assert(t->can_build_improvement());
	std::vector<hex::location> locs;
	locs.push_back(t->loc());
	set_locs(locs);
	set_labor_requirement(t->can_build_improvement()->cost());
}

void improvement_project::draw_loc(const hex::location& loc) const
{
	const int pixel_x = tile_pixel_x(loc);
	const int pixel_y = tile_pixel_y(loc);
	
	glColor4f(0.5, 0.5, 0.5, 0.5);
	tile_->can_build_improvement()->draw(pixel_x, pixel_y);
	glColor4f(1.0, 1.0, 1.0, 1.0);
}

std::string improvement_project::description() const
{
	return tile_->can_build_improvement()->id();
}

void improvement_project::do_apply(world& w)
{
	tile_->build_improvement(tile_->can_build_improvement());
}
